package main;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import utils.CarrierShuffleComparatorASC;
import utils.IterationalCarrierUtils;
import utils.IO;
import utils.Statistics;
import data.Carrier;
import data.CarrierType;
import data.Package;

public class Experiment {

	// listy dla kazdego pliku
	List<List<CarrierType>> carrierTypes;
	List<List<Package>> packages;
	List<List<Carrier>> carriers;

	float[] bestCarriersFieldBaseSum;
	float[] bestCarriersMinCapacitySum;

	String directory = "data/";
	private long timeStart;
	IO io;
	Statistics stats;

	String[] fileList = new String[] { "pp101.in", "pp102.in", "pp103.in",
			"pp104.in", "pp105.in", "pp106.in", "pp107.in", "pp108.in",
			"pp109.in", "pp110.in" };

	// String[] fileList = new String[] { "pp104.in" };

	private final int NUMBER_OF_THREADS = 4;
	private final int FILES_PER_THREAD = (int) Math
			.ceil((float) fileList.length / NUMBER_OF_THREADS);

	public Experiment() {
		stats = new Statistics();
		io = new IO(stats);
		carrierTypes = new ArrayList<List<CarrierType>>();
		packages = new ArrayList<List<Package>>();
		carriers = new ArrayList<List<Carrier>>();
		bestCarriersFieldBaseSum = new float[fileList.length + 1];
		bestCarriersMinCapacitySum = new float[fileList.length + 1];
	}

	public void loadData() {
		timeStart = System.currentTimeMillis();
		for (String fileName : fileList) {
			io.readFile(directory + fileName);
			carrierTypes.add(io.getCarriersFromFile());
			packages.add(io.getPackagesFromFile());
		}
	}

	public void start() {
		IterationalCarrierUtils iterationalCarrierUtils = new IterationalCarrierUtils();
		carriers = new ArrayList<List<Carrier>>();
		// inicjacyjny krok
		for (int i = 0; i < packages.size(); i++) {
			Collections
					.sort(packages.get(i), new CarrierShuffleComparatorASC());
			carriers.add(iterationalCarrierUtils.pushPackagesOnCarriers(
					packages.get(i), carrierTypes.get(i)));
		}

		// obliczamy besty
		for (int i = 0; i < carriers.size(); i++) {
			for (Carrier carrier : carriers.get(i)) {
				bestCarriersFieldBaseSum[i] += carrier.getType().getFieldBase();
				bestCarriersMinCapacitySum[i] += carrier.getCapacity();
			}
		}
		try {
			CalculationNode[] calculationNodes = new CalculationNode[NUMBER_OF_THREADS];
			Thread[] calculationThreads = new Thread[NUMBER_OF_THREADS];
			int nextIndex = 0;
			for (int i = 0; i < NUMBER_OF_THREADS; i++) {
				if ((i + 1) * FILES_PER_THREAD > fileList.length) {
					nextIndex = fileList.length;
				} else {
					nextIndex = (i + 1) * FILES_PER_THREAD;
				}
				calculationNodes[i] = new CalculationNode(i, timeStart,
						carrierTypes.subList(i * FILES_PER_THREAD, nextIndex),
						packages.subList(i * FILES_PER_THREAD, nextIndex),
						carriers.subList(i * FILES_PER_THREAD, nextIndex),
						Arrays.copyOfRange(bestCarriersFieldBaseSum, i
								* FILES_PER_THREAD, nextIndex),
						Arrays.copyOfRange(bestCarriersMinCapacitySum, i
								* FILES_PER_THREAD, nextIndex));

				calculationThreads[i] = new Thread(calculationNodes[i]);
				calculationThreads[i].start();
			}

			while (System.currentTimeMillis() - 950 < timeStart) {
				Thread.sleep(5);
			}

			// LACZENIE ROZWIAZAN Z POSZCZEGOLNYCH PLIKOW
			carriers = new ArrayList<List<Carrier>>();
			int numberOfIterations = 0, capacityMinIterations = 0, mixerIterations = 0;
			for (int i = 0; i < NUMBER_OF_THREADS; i++) {
				calculationThreads[i].interrupt();
				capacityMinIterations += calculationNodes[i]
						.getCapacityMinimalizationIterations();
				numberOfIterations += calculationNodes[i].getIterIterations();
				mixerIterations += calculationNodes[i]
						.getPackageMixerIterations();
				carriers.addAll(calculationNodes[i].getCarriers());
			}

			System.out.println("Number of iterations: " + numberOfIterations);
			System.out.println("Number of mixer iterations: "
					+ mixerIterations);
			System.out.println("Number of capacity minimalization iterations: "
					+ capacityMinIterations);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void saveResults() {
		for (int i = 0; i < fileList.length; i++) {
			io.writeOutput(carriers.get(i), fileList[i]);
		}
		System.out.println("Summary time was: "
				+ (System.currentTimeMillis() - timeStart) + " ms");
		stats.showStatistics();
	}
}
